package com.vcredit.creditcat.interceptor;

import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;

import com.fasterxml.jackson.core.JsonParseException;
import com.vcredit.creditcat.vo.JsonResult;

@ControllerAdvice
public class CreditCatExceptionConverter extends ExceptionHandlerExceptionResolver {

	Logger logger = Logger.getLogger(CreditCatExceptionConverter.class);

	/**
	 * 处理controller抛出的异常
	 *
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	@ExceptionHandler(MethodArgumentNotValidException.class)
	@ResponseBody
	public JsonResult handleMethodArgumentNotValidException(HttpServletRequest request,
			MethodArgumentNotValidException e) {
		return JsonResult.ErrorResponse("901", errorMessage(e));
	}

	private String errorMessage(MethodArgumentNotValidException e) {
		BindingResult bindingResult = e.getBindingResult();
		StringBuffer errorsb = new StringBuffer();
		if (bindingResult != null && bindingResult.hasErrors()) {
			// 异常处理
			for (ObjectError error : bindingResult.getAllErrors()) {
				String errorMessage = error.getDefaultMessage();
				if (StringUtils.isEmpty(errorMessage)) {
					errorMessage = "参数不合法，请检查参数!";
				}
				errorsb.append(errorMessage).append(";");
			}
		}
		return errorsb.toString();
	}

	/**
	 * 处理controller抛出的异常
	 *
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	@ExceptionHandler(JsonParseException.class)
	@ResponseBody
	public JsonResult handleJsonParseException(HttpServletRequest request, JsonParseException e) {
		return JsonResult.ErrorResponse("902", "请检查数据格式是否正确");
	}

	protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response,
			HandlerMethod handlerMethod, Exception exception) {
		ModelAndView mav = super.doResolveHandlerMethodException(request, response, handlerMethod, exception);
		if (exception instanceof Throwable) {
			Throwable throwable = (Throwable) exception;
			if (throwable.getCause() != null)
				exception = (Exception) throwable.getCause();
		}

		if (mav == null) {
			mav = new ModelAndView();
		}
		if (handlerMethod == null) {
			return null;
		}
		Method method = handlerMethod.getMethod();
		if (method == null) {
			return null;
		}
		if (exception != null) {
			try {
				String result = "{\"status\":\"" + matchingException(exception) + "\",\"message\":\""
						+ (StringUtils.isNotEmpty(exception.getMessage()) ? exception.getMessage() : "操作失败，请重新尝试")
						+ "\"}";
				response.getOutputStream().write(result.getBytes("UTF-8"));
				response.getOutputStream().close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return mav;
	}

	@Value("#{exception}")
	protected Properties expt;
	@SuppressWarnings("rawtypes")
	private Map<Class, String> expMap;

	@SuppressWarnings("rawtypes")
	private void init() {
		expMap = new LinkedHashMap<Class, String>();
		for (String key : expt.stringPropertyNames()) {
			try {
				expMap.put(Class.forName(key), expt.getProperty(key));
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
	}

	@SuppressWarnings("rawtypes")
	public String matchingException(Exception e) {
		if (expMap == null)
			init();
		for (Class c : expMap.keySet()) {
			if (c.isInstance(e)) {
				return expMap.get(c);
			}
		}
		return "001";
	}

	public void setExpt(Properties expt) {
		this.expt = expt;
	}

}
